#include <stdio.h>
#include <unistd.h>
#include <chrono>
#include <iostream>
#include <folly/Memory.h>
#include <folly/json.h>

std::string load_json_text(const std::string& path);

int main(int argc, char* argv[])
{
    int loop_cnt = 200;
    if (argc > 1) {
        loop_cnt = std::atoi(argv[1]);
        if (loop_cnt < 1) {
            loop_cnt = 200;
        }
    }

    std::string json_text = load_json_text("./data.json");
    if (json_text.empty()) return 0;

    std::shared_ptr<folly::dynamic> json_ptr;
    try{
        json_ptr = std::make_shared<folly::dynamic>(folly::parseJson(json_text));
    }catch(...){
        return false;
    }
    folly::dynamic* rectJson = json_ptr.get();

    folly::dynamic x = rectJson->at("x");
    folly::dynamic y = rectJson->at("y");
    folly::dynamic width = rectJson->at("width");
    folly::dynamic height = rectJson->at("height");
    std::cout << "(x, y, width, height): (" << x.getInt() << ", " 
                                            << y.getInt() << ", "
                                            << width.getInt() << ", "
                                            << height.getInt() << ")" << std::endl;


    std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
    for (int i=0; i<loop_cnt; i++) {
        std::shared_ptr<folly::dynamic> json_ptr;
        try{
            json_ptr = std::make_shared<folly::dynamic>(folly::parseJson(json_text));
        }catch(...){
            return false;
        }
        folly::dynamic* rectJson = json_ptr.get();

        folly::dynamic x = rectJson->at("x");
        folly::dynamic y = rectJson->at("y");
        folly::dynamic width = rectJson->at("width");
        folly::dynamic height = rectJson->at("height");
    }
    std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now();
    std::cout << "parse json text " << loop_cnt << " times costs: " << std::chrono::duration_cast<std::chrono::milliseconds>(
        end_time - start_time).count() << std::endl;
    return 0;
}

std::string load_json_text(const std::string& path)
{
    std::string ret;
    if (path.empty() || access(path.c_str(), F_OK)) {
        std::cout << "json file: " << path << " does not exist." << std::endl;
        return ret;
    }

    FILE* fp = fopen(path.c_str(), "rb");
    if (fp == NULL) {
        std::cout << "open json file: " << path << " failed" << std::endl;
        return ret;
    }

    fseek(fp, 0, SEEK_END);
    long int size = ftell(fp);
    rewind(fp);
    char* buf = new char[size];
    size_t len = fread(buf, sizeof(char), size, fp);
    if (len != size) {
        std::cout << "read failed, read count: " << len 
                  << ", actual count: " << size << std::endl;
        delete[] buf;
        fclose(fp);
        return ret;
    }

    ret.assign(buf, size);
    delete[] buf;
    fclose(fp);
    return ret;
}